


/***
 *
 * 给单个对象监听
 *
 */
function defineReactive(obj,key,val) {

    // 每个属性一个 监听器 
    var dep  =new  Dep()
    
    Object.defineProperty(obj,key,{
        enumerable:true,
        configurable:true,
        get (){

            console.log('Dep.target--->',JSON.stringify(Dep.target),);

            // 每次获取的时候，都绑定当前的 实例，
            // 不是绑定一次而已，而是每次有访问都调用，这样保证了在每个页面都能调用同一个属性，而且可以更新
            // 为了让  在 不同的实例中，可以随意调用其他实例的属性，而且会通知更新，所以，Dep.target 变成 动态
            dep.add(Dep.target)
            return val
        },

        set(newVal){

            if(newVal ==val) return ;
            
            // 通知 所有访问了这个变量的Vue实例32
            dep.notify(newVal)

        }
    })

}

/***
 *
 * 遍历对象，添加监听
 *
 */

function observer(obj) {

    if (!obj || (typeof obj !== 'object')) {
        return;
    }
    
    Object.keys(obj).forEach(function(item){
        
        defineReactive(obj,item,obj[item])
    
    })

}


/***
 *
 * 存放 watch 观察者对象
 *
 */
class Dep{

    constructor(){
        this.sub=[]
    }

    add(obj){
        this.sub.push(obj)
    }

    notify(){
        this.sub.forEach(function(item){
            
            // 通知每个组件，进行更新，更新的时候回 diff dom
            item.update()
        
        })
    }

}


/***
 *
 * 视图更新
 * 
 * 1、但是 Watcher 怎么 跟 Vue 实例 扯上关系 呢？
 *
 */

class Watcher{

    constructor(myWatcherName){

        // 每次新增一个实例， Dep.target 都会改变，就是保持唯一
        Dep.target = this

        this.myWatcherName=myWatcherName

    }

    update(){

        console.log('updateCallback--->',"视图更新了",this.myWatcherName);

    }


}


class Vue{

    constructor({data,methods,watcherName}){

        for (var i in data) {
            var item = data[i]
            this[i]=item
        }

        observer(this)

        new Watcher(watcherName)
       
        for (var i in methods) {
            var item = methods[i]
            this[i] =item
        }
        
    }
}

var  o  =new Vue({
    data:{
        name:"神仙朱",
        age:18,
        love:"大佬封"
    },
    methods:{
        getName(a){
            console.log(a,this.name)
        }
    },
    watcherName:"1"
})

o.getName(1)


var  o1  =new Vue({
    data:{
        name:"2222",
    },
    watcherName:"2",
    methods:{
        getName(a){
            console.log(a,this.name)
        }
    },
})


o.getName(2)


// o1.getName(3)

o.name="我勒个去"
// o1.name="我勒个去"